package hcmut.edu.vn.helps;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import org.cloudbus.cloudsim.Cloudlet;
import org.cloudbus.cloudsim.CloudletSchedulerTimeShared;
import org.cloudbus.cloudsim.Host;
import org.cloudbus.cloudsim.Pe;
import org.cloudbus.cloudsim.UtilizationModel;
import org.cloudbus.cloudsim.UtilizationModelFull;
import org.cloudbus.cloudsim.Vm;
import org.cloudbus.cloudsim.VmSchedulerTimeShared;
import org.cloudbus.cloudsim.examples.power.Constants;
import org.cloudbus.cloudsim.provisioners.BwProvisionerSimple;
import org.cloudbus.cloudsim.provisioners.PeProvisionerSimple;
import org.cloudbus.cloudsim.provisioners.RamProvisionerSimple;

public class Helps {
	private boolean compareCloudletBasedETime(Cloudlet cloudlet1,
			Cloudlet cloudlet2) {
		if (cloudlet1.getExecStartTime() < cloudlet2.getExecStartTime()) {
			return true;
		}
		return false;
	}

	public List<Cloudlet> sortCloudletListBaseETime(List<Cloudlet> clList) {
		for (int i = 0; i < clList.size() - 1; i++) {
			for (int j = i + 1; j < clList.size(); j++) {
				if (!compareCloudletBasedETime(clList.get(i), clList.get(j))) {
					Cloudlet temp = clList.get(i);
					clList.set(i, clList.get(j));
					clList.set(j, temp);
				}
			}
		}
		return clList;
	}

	private boolean compareCloudletBasedId(Cloudlet cloudlet1,
			Cloudlet cloudlet2) {
		if (cloudlet1.getCloudletId() > cloudlet2.getCloudletId()) {
			return true;
		}
		return false;
	}

	public List<Cloudlet> sortCloudletListBaseId(List<Cloudlet> clList) {
		for (int i = 0; i < clList.size() - 1; i++) {
			for (int j = i + 1; j < clList.size(); j++) {
				if (!compareCloudletBasedId(clList.get(i), clList.get(j))) {
					Cloudlet temp = clList.get(i);
					clList.set(i, clList.get(j));
					clList.set(j, temp);
				}
			}
		}
		return clList;
	}

	public List<WorkloadInfo> parseInputToList(String pathFile)
			throws IOException {
		List<WorkloadInfo> list = new ArrayList<>();
		FileInputStream inputStream = new FileInputStream(pathFile);
		DataInputStream dataInputStream = new DataInputStream(inputStream);
		BufferedReader reader = new BufferedReader(new InputStreamReader(
				dataInputStream));
		String strLine = "";
		while ((strLine = reader.readLine()) != null) {
			if (!strLine.startsWith(";") && !strLine.trim().isEmpty()) {
				String[] dataList = strLine.trim().split("	");
				WorkloadInfo workloadInfo = new WorkloadInfo(
						Integer.parseInt(dataList[0]),
						Integer.parseInt(dataList[1]),
						Integer.parseInt(dataList[2]),
						Integer.parseInt(dataList[3]),
						Integer.parseInt(dataList[4]),
						Integer.parseInt(dataList[5]),
						new UtilizationModelFull(), new UtilizationModelFull(),
						new UtilizationModelFull());
				list.add(workloadInfo);
			}
		}
		return list;
	}

	public List<Cloudlet> createCloudletList(int brokerId,
			String inputFolderName) throws IOException {
		List<Cloudlet> list = new ArrayList<>();
		int fileSize = 300;
		int outputSize = 300;
		UtilizationModel utilizationModel = new UtilizationModelFull();
		List<WorkloadInfo> workloadInfos = this
				.parseInputToList(inputFolderName);
		ConstantLease.CLOUDLETNUMBER = workloadInfos.size();
		for (int i = 0; i < workloadInfos.size(); i++) {
			WorkloadInfo item = workloadInfos.get(i);
			Cloudlet cloudlet = new Cloudlet(item.getId(),
					item.getCloudletLength(), item.getPesNumber(), fileSize,
					outputSize, item.getStartTime(), utilizationModel,
					utilizationModel, utilizationModel);
			cloudlet.setUserId(brokerId);
			cloudlet.setVmId(i);
			// //================== Set value according to Lease =============
			// cloudlet.setLeaseId(leaseId);
			// cloudlet.setExecStartTime(leaseStart);
			// cloudlet.setDuration(leaseDuration);
			// //==========================================================
			list.add(cloudlet);
		}
		return list;
	}

	public List<Vm> createVmList(int brokerId) {
		// Fourth step: Create one virtual machine
		List<Vm> vmlist = new ArrayList<Vm>();

		// VM description

		int mips = 1000;
		long size = 10000; // image size (MB)
		int ram = 512; // vm memory (MB)
		long bw = 1000;
		int pesNumber = 1; // number of cpus
		String vmm = "Xen"; // VMM name

		for (int i = 0; i < ConstantLease.CLOUDLETNUMBER; i++) {
			Vm vm = new Vm(i, brokerId, mips, pesNumber, ram, bw, size, vmm,
					new CloudletSchedulerTimeShared());
			// ========== set value based on lesase =================
			// vm.getLeaseIdList().add(leaseId);

			// ====================================================

			vmlist.add(vm);

		}

		return vmlist;

	}

	public List<Host> createHostList(int hostsNumber) {
		List<Host> hostList = new ArrayList<>();

		for (int i = 0; i < hostsNumber; i++) {
			int hostType = i % Constants.HOST_TYPES;

			int mips = 3000;
			List<Pe> peList = new ArrayList<Pe>();

			peList.add(new Pe(0, new PeProvisionerSimple(mips))); // has 1 PE
																	// (3000
																	// mips)

			hostList.add(new Host(i, new RamProvisionerSimple(
					Constants.HOST_RAM[hostType]), new BwProvisionerSimple(
					Constants.HOST_BW), Constants.HOST_STORAGE, peList,
					new VmSchedulerTimeShared(peList)));
		}
		return hostList;

	}

	public List<Vm> createVmListEachLease(List<Vm> allVm, int leaseId, double leaseStart,
			int scope[]) {
		List<Vm> vms = new ArrayList<>();
		for (int i = scope[0]; i < scope[1]; i++) {
			allVm.get(i).setLeaseId(leaseId);
			allVm.get(i).setStartTime(leaseStart);
			vms.add(allVm.get(i));
		}
		return vms;
	}

	public List<Cloudlet> createCloudletListEachLease(
			List<Cloudlet> allCloudlet, int leaseId, double leaseStart,
			double leaseDuration, int scope[]) {
		List<Cloudlet> cloudlets = new ArrayList<>();
		int count = 0;
		for (int i = scope[0]; i < scope[1]; i++) {
			allCloudlet.get(i).setLeaseId(leaseId);
			allCloudlet.get(i).setExecStartTime(leaseStart);
			allCloudlet.get(i).setDuration(leaseDuration);
			allCloudlet.get(i).setCloudletId(count);
			cloudlets.add(allCloudlet.get(i));
			count++;
		}
		return cloudlets;
	}
}
